// logs.js
const util = require('../../utils/util.js')
const { BluRxPack, BluTxPack, Flag } = require('../../utils/blepk.js')
const { $Message } = require('../../th/iview/base/index')
const app = getApp()
function ab2hex(buffer, spec) {
  var hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),
    function(bit) {
      return ('00' + bit.toString(16)).slice(-2)
    }
  )
  return hexArr.join(spec || '');
}
Page({
  data: {
    devs: {},
    showMenu: false,
    showWifiCfg: false,
    bleOpr: [{"name": "配置WIFI"}, {"name": "添加设备"}],
    ssid: 'SmartJL',
    pswd: 'JL013579',
    devSearching: false
  },
  cur: null,
  bleCVC: null,
  serviceId: '021A9004-0382-4AEA-BFF4-6B3F1C5ADFB4',
  onLoad() {
    this.init_ble()
  },
  onHide() {
    this.stop_search_ble()
  },
  async init_ble() {
    console.time('w')
    console.timeLog('w',"init_ble")
    let res = await wx.openBluetoothAdapter()
    let page = this
    console.timeLog('w',"open ble adapter:", res)
    wx.onBluetoothDeviceFound((result) => {
      let update = false;
      let devs = page.data.devs
      
      result.devices.forEach(device => {
        let {name, 	deviceId, RSSI} = device
        console.log("find ble:", name, deviceId, RSSI)
        if (!devs[deviceId]) {
          devs[deviceId] = {name, deviceId, RSSI}
          update = true
        } else if (devs[deviceId].RSSI) {
          devs[deviceId].RSSI = RSSI
          devs[deviceId].name = name
          update = true
        }
      });
      if (update) page.setData({ devs })
    })
    wx.onBLEConnectionStateChange((res)=>{
      console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`, res)
      let { deviceId } = res
      if (!res.connected && this.cur && deviceId == this.cur.deviceId)  {
        wx.closeBLEConnection({ deviceId }).catch(()=>{})
        this.cur = null
      }
    })
    wx.onBLECharacteristicValueChange((characteristic)=>{
      console.log("character-val-change", characteristic, this.bleCVC)
      if (this.bleCVC)  this.bleCVC(characteristic)
    })
    await this.start_search_ble();
  },
  async start_search_ble() {
    if (this.data.devSearching)  return;
    let res = await wx.startBluetoothDevicesDiscovery({
        services: [this.serviceId],
        allowDuplicatesKey: true,
        interval: 100
    })
    this.setData({"devSearching": true})
    console.log("search ble:", res)
  },
  async stop_search_ble() {
    if (!this.data.devSearching)  return;
    let res = await wx.stopBluetoothDevicesDiscovery()
    this.setData({"devSearching": false})
    console.log("stop search ble:", res)
  },
  async ble_connect(deviceId, timeout) {
    timeout = timeout || 2000
    await wx.createBLEConnection({
      deviceId,
      timeout
    }).catch(res=>{
      if (res.errno && res.errno!=1509007)  throw res
    })
    let serviceId = this.serviceId
    let {characteristics} = await wx.getBLEDeviceCharacteristics({
      deviceId,
      serviceId
    })
    let characteristicId = characteristics[0].uuid
    return characteristicId
  },
  async timeout(tag, f, tout) {
    console.time(tag)
    return await new Promise((success,fail) =>{
      let timer = setTimeout(()=>{
        console.timeLog(tag, "step-timeout")
        fail('timeout')
      },tout)
      return f().then(success).finally(()=>clearTimeout(timer))
    }).finally(()=>{
      console.timeLog(tag, "finish")
      console.timeEnd(tag)
    });
  },
  async ble_read(deviceId, characteristicId) {
    let serviceId = this.serviceId
    let ret = {}
    let page = this
    return await this.timeout('ble_read', async ()=>{
      let read = new Promise((success)=>{
        page.bleCVC = (x)=>{
          console.timeLog('w', "ble_read", "success", x)
          ret.ret = x
          success(x)
        }
      });
      await wx.readBLECharacteristicValue({
        characteristicId,
        deviceId,
        serviceId,
      })
      return await(read)
    }, 2000)
  },
  async ble_write(deviceId, characteristicId, value) {
      let serviceId = this.serviceId
      console.timeLog('w', "ble-write+", deviceId, characteristicId, ab2hex(value))
      let r = await wx.writeBLECharacteristicValue({
        characteristicId,
        deviceId,
        serviceId,
        value,
      })
      console.timeLog('w', "ble-write-return", r)
      return await this.ble_read(deviceId, characteristicId)
  },
  async ble_send(deviceId, characteristicId, fun, str) {
    let pack = new BluTxPack(fun, str);
    let ctx = {}
    console.timeLog('w', "ble_send", deviceId, characteristicId, fun, str)
    await this.timeout('ble_send', async ()=>{
      let err = false
      while (!pack.finish()) {
        err = false
        ctx.ack = await this.ble_write(deviceId, characteristicId, pack.peek().buffer, ctx).catch((e)=>{
          console.timeLog('w', "ble_write-e", e)
          if (e != 'timeout') throw e
          err = true
        })
        console.timeLog('w', "ble_write_return", ctx.ack, err)
        err || pack.next()
      }
    }, 6000)
    console.timeLog('w', "ble_send_return", ctx.ack)
    return ctx.ack
  },
  async ble_dev_id() {
    await this.ble_send(this.cur.deviceId, this.cur.characteristicId, Flag.fun_cmd, 'devid')
    let d = await this.ble_read(this.cur.deviceId, this.cur.characteristicId)
    return (new BluRxPack(d.value)).dat
  },
  async dev_set_ssid(ssid) {
    console.warn("dev_set_ssid", ssid)
    return await this.ble_send(this.cur.deviceId, this.cur.characteristicId, Flag.fun_ssid, ssid)
  },
  async dev_set_pswd(pswd) {
    console.warn("dev_set_pswd", pswd)
    return await this.ble_send(this.cur.deviceId, this.cur.characteristicId, Flag.fun_pswd, pswd||'')
  },
  async dev_connect_wifi() {
    console.warn("dev_connect_wifi")
    return await this.ble_send(this.cur.deviceId, this.cur.characteristicId, Flag.fun_cmd, "connect")
  },
  async handleConnectBle(item) {
    await this.stop_search_ble()
    let deviceId = item.target.dataset.key
    if (this.cur) {
      await wx.closeBLEConnection(this.cur.deviceId).catch(()=>{})
      this.cur = null
    }
    let characteristicId = await this.ble_connect(deviceId)
    console.log('ble_connect', characteristicId)
    this.cur = { deviceId, characteristicId }
    let dev_id = await this.ble_dev_id()
    console.log('dev_id', dev_id)
    this.setData({showMenu: true})
  },
  async handleToggleScanBle() {
    if (this.data.devSearching) {
      await this.stop_search_ble()
    } else {
      await this.start_search_ble() 
    }
  },
  handleAddDev({currentTarget}) {
    console.log("add-dev", currentTarget)
    let mac = currentTarget.dataset.key
    let devs = app.globalData.devs
    if (!devs) app.globalData.devs = devs = []
    for (let i = 0; i < devs.length; ++i) {
      if (devs[i].mac == mac) {
        $Message({content: "已经添加过了"})
        return
      }
    }
    let {name, deviceId} = this.data.devs[mac]
    app.globalData.newDevs = true
    devs.unshift({name, 'mac':deviceId})
    wx.setStorageSync('devs', devs)
    $Message({content: "添加成功"})
  },
  async handleDevOpr({ detail }) {
    if (detail.index == 0) {
      this.setData({showMenu: false})
      this.setData({showWifiCfg: true})
    } else if (detail.index == 1) {
      this.handleAddDev({'currentTarget':{'dataset':{'key': this.cur.deviceId}}})
    }
  },
  handSsidChange({ detail }) {
    this.setData({ssid: detail.detail.value})
  },
  handPswdChange({ detail }) {
    this.setData({pswd: detail.detail.value})
  },
  async handleDevOprCancle() {
    this.setData({showMenu: false})
  },
  async handleWifiCfgOk() {
    await this.dev_set_ssid(this.data.ssid)
    await this.dev_set_pswd(this.data.pswd)
    await this.dev_connect_wifi()
    this.setData({showWifiCfg: false})
  },
  async handleWifiCfgCancel() {
    this.setData({showWifiCfg: false})
  }

})